﻿#ifndef _STRING_DEFINES_H_
#define _STRING_DEFINES_H_

#pragma once
#include "kernel/Prerequisites_kernel.h"
#include "kernel/multibytestring.h"
#include "kernel/unicodestring.h"
#include "kernel/gbkstring.h"

namespace FD
{
	namespace Kernel
	{
#if OGRE_STRING_USE_CUSTOM_MEMORY_ALLOCATOR
#if OGRE_WCHAR_T_STRINGS
		typedef std::basic_string<wchar_t, std::char_traits<wchar_t>, STLAllocator<wchar_t, GeneralAllocPolicy > >	_StringBase;
#else
		typedef std::basic_string<CHAR, std::char_traits<CHAR>, STLAllocator<CHAR, GeneralAllocPolicy > >	_StringBase;
#endif
#if OGRE_WCHAR_T_STRINGS
		typedef std::basic_stringstream<wchar_t, std::char_traits<wchar_t>, STLAllocator<wchar_t, GeneralAllocPolicy >> _StringStreamBase;
#else
		typedef std::basic_stringstream<CHAR, std::char_traits<CHAR>, STLAllocator<CHAR, GeneralAllocPolicy > > _StringStreamBase;
#endif
#define StdStringT(T) std::basic_string<T, std::char_traits<T>, std::allocator<T> >
#define CustomMemoryStringT(T) std::basic_string<T, std::char_traits<T>, STLAllocator<T,GeneralAllocPolicy> >

		template<typename T>
		bool operator <(const CustomMemoryStringT(T)& l, const StdStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) < 0;
		}
		template<typename T>
		bool operator <(const StdStringT(T)& l, const CustomMemoryStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) < 0;
		}
		template<typename T>
		bool operator <=(const CustomMemoryStringT(T)& l, const StdStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) <= 0;
		}
		template<typename T>
		bool operator <=(const StdStringT(T)& l, const CustomMemoryStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) <= 0;
		}
		template<typename T>
		bool operator >(const CustomMemoryStringT(T)& l, const StdStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) > 0;
		}
		template<typename T>
		bool operator >(const StdStringT(T)& l, const CustomMemoryStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) > 0;
		}
		template<typename T>
		bool operator >=(const CustomMemoryStringT(T)& l, const StdStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) >= 0;
		}
		template<typename T>
		bool operator >=(const StdStringT(T)& l, const CustomMemoryStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) >= 0;
		}
		template<typename T>
		bool operator ==(const CustomMemoryStringT(T)& l, const StdStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) == 0;
		}
		template<typename T>
		bool operator ==(const StdStringT(T)& l, const CustomMemoryStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) == 0;
		}
		template<typename T>
		bool operator !=(const CustomMemoryStringT(T)& l, const StdStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) != 0;
		}
		template<typename T>
		bool operator !=(const StdStringT(T)& l, const CustomMemoryStringT(T)& o)
		{
			return l.compare(0, l.length(), o.c_str(), o.length()) != 0;
		}
		template<typename T>
		CustomMemoryStringT(T) operator +=(const CustomMemoryStringT(T)& l, const StdStringT(T)& o)
		{
			return CustomMemoryStringT(T)(l) += o.c_str();
		}
		template<typename T>
		CustomMemoryStringT(T) operator +=(const StdStringT(T)& l, const CustomMemoryStringT(T)& o)
		{
			return CustomMemoryStringT(T)(l.c_str()) += o.c_str();
		}
		template<typename T>
		CustomMemoryStringT(T) operator +(const CustomMemoryStringT(T)& l, const StdStringT(T)& o)
		{
			return CustomMemoryStringT(T)(l) += o.c_str();
		}
		template<typename T>
		CustomMemoryStringT(T) operator +(const StdStringT(T)& l, const CustomMemoryStringT(T)& o)
		{
			return CustomMemoryStringT(T)(l.c_str()) += o.c_str();
		}
		template<typename T>
		CustomMemoryStringT(T) operator +(const T *l, const CustomMemoryStringT(T)& o)
		{
			return CustomMemoryStringT(T)(l) += o;
		}
#undef StdStringT
#undef CustomMemoryStringT
#else
#if OGRE_WCHAR_T_STRINGS
		typedef FD::Kernel::FdUnicodeString _StringBase;
#else
		typedef FD::Kernel::FdMultiByteString  _StringBase;
#endif
#if OGRE_WCHAR_T_STRINGS
		typedef std::basic_stringstream<WCHAR, std::char_traits<WCHAR>, std::allocator<WCHAR>> _StringStreamBase;
#else
		typedef std::basic_stringstream<CHAR, std::char_traits<CHAR>, std::allocator<CHAR> > _StringStreamBase;
#endif
#endif
		typedef _StringBase String;
		typedef _StringStreamBase StringStream;
#define String FD::Kernel::String
#define StringStream FD::Kernel::StringStream

		// If we're using the GCC 3.1 C++ Std lib
#if OGRE_COMPILER == OGRE_COMPILER_GNUC && OGRE_COMP_VER >= 310 && !defined(STLPORT)
// For gcc 4.3 see http://gcc.gnu.org/gcc-4.3/changes.html
#   if OGRE_COMP_VER >= 430
#       include <tr1/unordered_map>
#   else
#       include <ext/hash_map>
namespace __gnu_cxx
{
    template <> struct hash< Ogre::_StringBase >
    {
        size_t operator()( const Ogre::_StringBase _stringBase ) const
        {
            /* This is the PRO-STL way, but it seems to cause problems with VC7.1
               and in some other cases (although I can't recreate it)
               hash<const char*> H;
               return H(_stringBase.c_str());
            */
            /** This is our custom way */
            register size_t ret = 0;
            for( Ogre::_StringBase::const_iterator it = _stringBase.begin(); it != _stringBase.end(); ++it )
                ret = 5 * ret + *it;

            return ret;
        }
    };
}
#   endif
#endif

#if OGRE_COMPILER == OGRE_COMPILER_GNUC && OGRE_COMP_VER >= 310 && !defined(STLPORT)
#   if OGRE_COMP_VER < 430
		typedef ::__gnu_cxx::hash< _StringBase > _StringHash;
#   else
		typedef ::std::tr1::hash< _StringBase > _StringHash;
#   endif
#elif OGRE_COMPILER == OGRE_COMPILER_CLANG
#   if defined(_LIBCPP_VERSION)
		typedef ::std::hash< _StringBase > _StringHash;
#   else
		typedef ::std::tr1::hash< _StringBase > _StringHash;
#   endif
#elif OGRE_COMPILER == OGRE_COMPILER_MSVC && OGRE_COMP_VER >= 1600 && !defined(STLPORT) // VC++ 10.0
		typedef ::std::tr1::hash< _StringBase > _StringHash;
#elif !defined( _STLP_HASH_FUN_H )
		typedef stdext::hash_compare< _StringBase, std::less< _StringBase > > _StringHash;
#else
		typedef std::hash< _StringBase > _StringHash;
#endif

#define StringHash FD::Kernel::_StringHash

#define FD_DEREF_DISPLAYSTRING_ITERATOR(it) *it
	}
}

#endif
